//kruskal算法思路贪心，既找到现阶段距离树最短的边，直接加入树即可
#include <iostream>
#include <cstring>
using namespace std;

typedef struct Edge //无向图的边
{
    int a; //端点1
    int b; //端点2
    int w; //边的权值
} edge;

const int N = 100010;
const int INF = 0x3f3f3f3f;
edge e[N * 2];     //存储边
int p[N], Size[N]; //定义并查集
int n, m, a, b, c; //获取输入

void quick_sort(edge e[], int l, int r) //对输入的边进行一次快排
{
    if (l >= r)
        return;
    int i = l - 1, j = r + 1, x = e[l + r >> 1].w;
    while (i < j)
    {
        do
            ++i;
        while (e[i].w < x);
        do
            --j;
        while (e[j].w > x);
        if (i < j)
            swap(e[i], e[j]);
    }
    quick_sort(e, l, j), quick_sort(e, j + 1, r);
    return;
}

void init(int n) //并查集的初始化函数
{
    for (int i = 0; i <= n; ++i)
    {
        p[i] = i;
        Size[i] = 1;
    }
    return;
}

int find(int x) //并查集的父节点查询函数
{
    if (x != p[x])
        p[x] = find(p[x]);
    return p[x];
}

bool merge(int a, int b) //并查集的合并函数
{
    if (find(a) != find(b))
    {
        Size[find(b)] += Size[find(a)];
        p[find(a)] = find(b);
        return true;
    }
    return false;
}

int kruskal()
{
    int res = 0; //存储答案
    for (int i = 0; i < m; ++i)
        if (merge(e[i].a, e[i].b)) //尝试合并两个并查集
            res += e[i].w;
    if (Size[find(1)] == n)
        return res;
    else
        return INF;
}

int main()
{
    cin >> n >> m;
    init(n); //初始化并查集
    for (int i = 0; i < m; ++i)
    {
        cin >> a >> b >> c;
        e[i].a = a, e[i].b = b, e[i].w = c;
    }
    quick_sort(e, 0, m - 1); //对已经输入的边做快排，以便以后面的kruskal算法
    int t = kruskal();
    if (t == INF)
        cout << "impossible";
    else
        cout << t;
    return 0;
}
